package com.ymy.thinking.in.spring.dependency.source;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Lazy;

import java.util.Map;

/**
 * 1. 依赖注入和依赖查找来源是否相同？
 * 答：不同, 依赖查找来源仅限于 Spring BeanDefinition  和 单例对象。
 * 依赖注入的来源还包括 Resolvable Dependency 和 @value 所标注的外部配置。
 * 2. IoC 容器启动后还能注册单例对象吗？
 * 答：可以, 依赖查找和依赖注入都可以拿到 Bean, 但是依赖注入需要添加 @Lazy 注解。
 * <p>
 * 3. Spring 依赖注入来源
 * 答：Spring BeanDefinition、单例对象、Resolvable Dependency、@Value 外部化配置
 *
 * @author Ringo
 * @date 2022/2/5 17:08
 */
public class InterviewQuestions {


    @Lazy
    @Autowired
    private Map<String, Person> personMap;

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        applicationContext.register(InterviewQuestions.class);

        // 启动 IoC 容器
        applicationContext.refresh();

        // 注册 BeanDefinition
        registerBeanDefinition(applicationContext);

        // 注册单例对象
        registerBean(applicationContext);


        System.out.println(applicationContext.getBeansOfType(Person.class));

        applicationContext.getBeanProvider(InterviewQuestions.class)
                .ifAvailable(bean -> System.out.println(bean.personMap));

        applicationContext.close();
    }

    public static void registerBeanDefinition(AnnotationConfigApplicationContext applicationContext) {
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Person.class).getBeanDefinition();
        applicationContext.registerBeanDefinition("person1", beanDefinition);
    }


    public static void registerBean(AnnotationConfigApplicationContext applicationContext) {
        applicationContext.getBeanFactory().registerSingleton("person2", new Person());
    }

    private static class Person {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}
